home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / WASTE 1.2 / WASTE Demo ƒ / WEDemoWindows.c < prev   
Text File  |  1996-05-19  |  22KB  |  951 lines

  1. /*
  2.     WASTE Demo Project:
  3.     Window Handling
  4.  
  5.     Copyright © 1993-1996 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __ALIASES__
  13. #include <Aliases.h>
  14. #endif
  15.  
  16. #ifndef __TOOLUTILS__
  17. #include <ToolUtils.h>
  18. #endif
  19.  
  20. #ifndef __FILETYPESANDCREATORS__
  21. #include <FileTypesAndCreators.h>
  22. #endif
  23.  
  24. #ifndef _LongCoords_
  25. #include "LongCoords.h"
  26. #endif
  27.  
  28. #ifndef __WEDEMOAPP__
  29. #include "WEDemoIntf.h"
  30. #endif
  31.  
  32. // some consts used by DoGrow()
  33.  
  34. enum {
  35.     kMinWindowWidth        = 200,
  36.     kMinWindowHeight    = 80
  37. };
  38.  
  39. // static variables
  40.  
  41. static long sScrollStep; // how many pixels to scroll (used by ScrollProc)
  42.  
  43.  
  44. static void    CalcGrowIconRect( WindowRef window, Rect *iconRect )
  45. {
  46.     Rect portRect = GetWindowPort( window )->portRect;
  47.  
  48.     iconRect->top = portRect.bottom - (kBarWidth - 2);
  49.     iconRect->left = portRect.right - (kBarWidth - 2);
  50.     iconRect->bottom = portRect.bottom;
  51.     iconRect->right = portRect.right;
  52. }
  53.  
  54. static void    CalcTextRect( WindowRef window, Rect *textRect )
  55. {
  56.     Rect portRect = GetWindowPort( window )->portRect;
  57.  
  58.     textRect->top = 0;
  59.     textRect->left = 0;
  60.     textRect->bottom = portRect.bottom - (kBarWidth - 1);
  61.     textRect->right = portRect.right - (kBarWidth - 1);
  62.     InsetRect( textRect, kTextMargin, kTextMargin );
  63. }
  64.  
  65. static void    CalcScrollBarRect( WindowRef window, VHSelect axis, Rect *barRect )
  66. {
  67.     Rect portRect = GetWindowPort( window )->portRect;
  68.  
  69.     switch ( axis )
  70.     {
  71.         case v:
  72.             barRect->top = -1;
  73.             barRect->left = portRect.right - (kBarWidth - 1);
  74.             barRect->bottom = portRect.bottom - (kBarWidth - 2);
  75.             barRect->right = portRect.right + 1;
  76.             break;
  77.  
  78.         case h:
  79.             barRect->top = portRect.bottom - (kBarWidth - 1);
  80.             barRect->left = -1;
  81.             barRect->bottom = portRect.bottom + 1;
  82.             barRect->right = portRect.right - (kBarWidth - 2 );
  83.             break;
  84.     }
  85. }
  86.  
  87. /*
  88.     the standard Toolbox trap _DrawGrowIcon draws two lines from the grow icon
  89.     to the left and top margins of the window's content area
  90.     these additional lines may create ugly dirt, so we use this routine to temporarily
  91.     set the clip region to the grow icon rect.
  92.  
  93.     in addition, if validate is true, we call _ValidRect on the icon rect
  94. */
  95.  
  96. static void    MyDrawGrowIcon( WindowRef window, Boolean validate )
  97. {
  98.     GrafPtr        savePort;
  99.     RgnHandle    saveClip;
  100.     Rect        r;
  101.  
  102.     // save port and set thePort to wind
  103.  
  104.     GetPort( &savePort );
  105.     SetPortWindowPort( window );
  106.  
  107.     // save the clip region
  108.  
  109.     saveClip = NewRgn();
  110.     GetClip( saveClip );
  111.  
  112.     // calculate the grow icon rect
  113.  
  114.     CalcGrowIconRect( window, &r );
  115.  
  116.     // set clip region to grow icon rect
  117.  
  118.     ClipRect( &r );
  119.  
  120.     // call _DrawGrowIcon
  121.  
  122.     DrawGrowIcon( window );
  123.  
  124.     // if validate is true, remove the grow icon rect from the update region
  125.  
  126.     if ( validate )
  127.         ValidRect( &r );
  128.  
  129.     // restore old clip region
  130.  
  131.     SetClip( saveClip );
  132.     DisposeRgn( saveClip );
  133.  
  134.     // restore old port
  135.  
  136.     SetPort( savePort );
  137. }
  138.  
  139. static void    ScrollBarChanged( WindowRef window )
  140. {
  141.     // scroll text to reflect new scroll bar setting
  142.  
  143.     DocumentHandle hDocument = GetWindowDocument( window );
  144.     WEReference    we;
  145.     LongRect viewRect, destRect;
  146.  
  147.     we = (*hDocument)->we;
  148.     WEGetViewRect( &viewRect, we );
  149.     WEGetDestRect( &destRect, we );
  150.     WEScroll
  151.     (
  152.         viewRect.left - destRect.left - LCGetValue( (*hDocument)->scrollBars[ h ] ),
  153.         viewRect.top - destRect.top - LCGetValue( (*hDocument)->scrollBars[ v ] ),
  154.         we
  155.     );
  156. }
  157.  
  158. static void    AdjustBars( WindowRef window )
  159. {
  160.     DocumentHandle    hDocument;
  161.     WEReference        we;
  162.     GrafPtr            savePort;
  163.     LongRect        viewRect, destRect;
  164.     long            value;
  165.     long            max;
  166.     ControlRef        bar;
  167.  
  168.     GetPort( &savePort );
  169.     SetPortWindowPort( window );
  170.  
  171.     hDocument = GetWindowDocument(window);
  172.     we = (*hDocument)->we;
  173.  
  174.     // get the view and destination rectangle
  175.  
  176.     WEGetViewRect( &viewRect, we );
  177.     WEGetDestRect( &destRect, we );
  178.  
  179.     //    do the vertical axis
  180.  
  181.     //    get scroll bar handle
  182.  
  183.     bar = (*hDocument)->scrollBars[ v ];
  184.  
  185.     //    calculate new scroll bar settings
  186.  
  187.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  188.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  189.  
  190.     value = viewRect.top - destRect.top;
  191.     max = value + (destRect.bottom - viewRect.bottom);
  192.  
  193.     //    make sure max is always non-negative
  194.  
  195.     if ( max <= 0 )
  196.         max = 0;
  197.  
  198.     //    reset the scroll bar
  199.  
  200.     LCSetMax( bar, max );
  201.     LCSetValue( bar, value );
  202.  
  203.     //    if value exceeds max then the bottom of the destRect is above
  204.     //    the bottom of the view rectangle:  we need to scroll the text downward
  205.  
  206.     if ( value > max )
  207.         ScrollBarChanged( window );
  208.  
  209.     //    now do the horizontal axis
  210.  
  211.     //    get scroll bar handle
  212.  
  213.     bar = (*hDocument)->scrollBars[ h ];
  214.  
  215.     //    calculate new scroll bar settings
  216.  
  217.     value = viewRect.left - destRect.left;
  218.     max = value + (destRect.right - viewRect.right);
  219.  
  220.     //    make sure max is always non-negative
  221.  
  222.     if ( max <= 0 )
  223.         max = 0;
  224.  
  225.     //    reset the scroll bar
  226.  
  227.     LCSetMax( bar, max );
  228.     LCSetValue( bar, value );
  229.  
  230.     SetPort( savePort );
  231. }
  232.  
  233. static void    ViewChanged( WindowRef window )
  234. {
  235.     DocumentHandle    hDocument;
  236.     GrafPtr            savePort;
  237.     ControlRef        bar;
  238.     Rect            r;
  239.     LongRect        viewRect;
  240.     VHSelect        axis;
  241.  
  242.     GetPort( &savePort );
  243.     SetPortWindowPort( window );
  244.  
  245.     hDocument = GetWindowDocument( window );
  246.  
  247.     //    resize the text area
  248.  
  249.     CalcTextRect( window, &r );
  250.     WERectToLongRect( &r, &viewRect );
  251.     WESetViewRect( &viewRect, (*hDocument)->we );
  252.  
  253.     //     move and resize the control bars
  254.  
  255.     for ( axis = v; axis <= h; axis++ )
  256.     {
  257.         bar = (*hDocument)->scrollBars[ axis ];
  258.         CalcScrollBarRect( window, axis, &r );
  259.         MoveControl( bar, r.left, r.top );
  260.         SizeControl( bar, r.right - r.left, r.bottom - r.top );
  261.         ValidRect( &r );
  262.     }
  263.  
  264.     //    reset the thumb positions and the max values of the control bars
  265.     AdjustBars( window );
  266.  
  267.     //    redraw the control bars
  268.  
  269.     ShowControl( (*hDocument)->scrollBars[ v ] );
  270.     ShowControl( (*hDocument)->scrollBars[ h ] );
  271.  
  272.     SetPort( savePort );
  273. }
  274.  
  275. /*
  276.     This is a deviation from the original Pascal WASTE Demo App code.
  277.  
  278.     This "morally correct" code for window dragging is per an article in MacTech
  279.     Magazine (July 1994, Vol 10, No. 7). by Eric Shapiro (of Rock Ridge Enterprises)
  280.     called "Multiple Monitors vs. Your Application"
  281.  
  282.     Eric addressed numerous things to allow your app to deal nicely with multiple
  283.     monitor setups, one of them is dragging.
  284.  
  285.     According to Eric, many apps don't let you drag windows to second monitors, and
  286.     though holding down the cmd/opt keys often overrides this problem, it should
  287.     still be updated.  And the only reason qd.screenBits.bounds works to allow
  288.     you to drag to second monitors is because of a kludge Apple put in the Window Manager
  289.  
  290.     So, this is some code from Eric to make our app be "morally correct" :)
  291. */
  292.  
  293. void DoDrag( Point thePoint, WindowRef window )
  294. {
  295.     Rect limitR;
  296.  
  297.     if ( gHasColorQD )
  298.         limitR = ( **GetGrayRgn()).rgnBBox;
  299.     else
  300.         limitR = qd.screenBits.bounds;
  301.  
  302.     DragWindow( window, thePoint, &limitR );
  303. }
  304.  
  305. void Resize( Point newSize, WindowRef window )
  306. {
  307.     DocumentHandle    hDocument;
  308.     GrafPtr            savePort;
  309.     Rect            r;
  310.     RgnHandle        tempRgn, dirtyRgn;
  311.  
  312.     GetPort( &savePort );
  313.     SetPortWindowPort( window );
  314.  
  315.     hDocument = GetWindowDocument( window );
  316.  
  317.     //    create temporarty regions for calculations
  318.     tempRgn = NewRgn();
  319.     dirtyRgn = NewRgn();
  320.  
  321.     //    save old text region
  322.  
  323.     CalcTextRect( window, &r );
  324.     RectRgn( tempRgn, &r );
  325.  
  326.     //    erase the old grow icon rect
  327.     CalcGrowIconRect( window, &r );
  328.     EraseRect( &r );
  329.  
  330.     //    hide the scroll bars
  331.  
  332.     HideControl( (*hDocument)->scrollBars[ v ] );
  333.     HideControl( (*hDocument)->scrollBars[ h ] );
  334.  
  335.     //    perform the actual resizing of the window, redraw scroll bars and grow icon
  336.     SizeWindow( window, newSize.h, newSize.v, false );
  337.     ViewChanged( window );
  338.     MyDrawGrowIcon( window, true );
  339.  
  340.     //    calculate the dirty region (to be updated)
  341.     CalcTextRect( window, &r );
  342.     RectRgn( dirtyRgn, &r );
  343.     XorRgn( dirtyRgn, tempRgn, dirtyRgn );
  344.     InsetRect( &r, -kTextMargin, -kTextMargin );
  345.     RectRgn( tempRgn, &r );
  346.     SectRgn( dirtyRgn, tempRgn, dirtyRgn );
  347.  
  348.     //    mark the dirty region as invalid
  349.     InvalRgn( dirtyRgn );
  350.  
  351.     //    throw away temporary regions
  352.     DisposeRgn( tempRgn );
  353.     DisposeRgn( dirtyRgn );
  354.  
  355.     SetPort( savePort );
  356. }
  357.  
  358. void DoGrow( Point hitPt, WindowRef window )
  359. {
  360.     Rect sizeRect;
  361.     long newSize;
  362.  
  363.     SetRect( &sizeRect, kMinWindowWidth, kMinWindowHeight, SHRT_MAX, SHRT_MAX );
  364.     if ( ( newSize = GrowWindow( window, hitPt, &sizeRect ) ) != 0L )
  365.     {
  366.         //    for some reason, GrowWindow( ) returns a long value,
  367.         //    but it's really a Point
  368.  
  369.         Resize( * (Point *) &newSize, window );
  370.     }
  371. }
  372.  
  373. void DoZoom( short partCode, WindowRef window )
  374. {
  375.     DocumentHandle    hDocument;
  376.     GrafPtr            savePort;
  377.     Rect            r;
  378.  
  379.     GetPort( &savePort );
  380.     SetPortWindowPort( window );
  381.  
  382.     hDocument = GetWindowDocument(window);
  383.  
  384.     r = GetWindowPort( window )->portRect;
  385.     EraseRect( &r );
  386.     HideControl( (*hDocument)->scrollBars[ v ] );
  387.     HideControl( (*hDocument)->scrollBars[ h ] );
  388.  
  389.     ZoomWindow( window, partCode, false );
  390.  
  391.     ViewChanged( window );
  392.     CalcTextRect( window, &r );
  393.     InvalRect( &r );
  394.  
  395.     SetPort( savePort );
  396. }
  397.  
  398. // this is a callback tourine called by the Toolbox Control Manager
  399. // move the scroll bar thumb and scroll the text accordingly
  400.  
  401. static pascal void ScrollProc( ControlRef bar, ControlPartCode partCode )
  402. {
  403.     long value, step;
  404.  
  405.     if ( partCode == kControlNoPart )
  406.         return;
  407.  
  408.     value = LCGetValue( bar );
  409.     step = sScrollStep;
  410.  
  411.     if ( (( value < LCGetMax( bar )) && ( step > 0 )) ||
  412.          (( value > 0 ) && ( step < 0 ) ) )
  413.     {
  414.         LCSetValue( bar, value + step );
  415.         ScrollBarChanged( FrontWindow( ) );
  416.     }
  417. }
  418.  
  419. static void    DoScrollBar( Point hitPt, EventModifiers modifiers, WindowRef window )
  420. {
  421.     DocumentHandle        hDocument;
  422.     ControlRef            bar = nil;
  423.     LongRect            viewRect;
  424.     ControlPartCode        partCode;
  425.     long                pageSize;
  426.     long                step = 0;
  427.  
  428. #ifdef __cplusplus
  429.     static ControlActionUPP sScrollerUPP = NewControlActionProc( ScrollProc );
  430. #else
  431.     static ControlActionUPP sScrollerUPP = nil;
  432.     if (sScrollerUPP == nil)
  433.     {
  434.         sScrollerUPP = NewControlActionProc( ScrollProc );
  435.     }
  436. #endif
  437.  
  438.     hDocument = GetWindowDocument( window );
  439.     WEGetViewRect( &viewRect, (*hDocument)->we );
  440.  
  441.     //    find out which control was hit (if any) and in which part
  442.     partCode = FindControl( hitPt, window, &bar );
  443.  
  444.     //    if any control was hit, it must be one of our two scroll bars:
  445.     //    find out which and calculate the page size for it
  446.     if ( bar == (*hDocument)->scrollBars[ v ] )
  447.     {
  448.         pageSize = viewRect.bottom - viewRect.top;
  449.     }
  450.     else if ( bar == (*hDocument)->scrollBars[ h ] )
  451.     {
  452.         pageSize = viewRect.right - viewRect.left;
  453.     }
  454.     else
  455.     {
  456.         return;        // return immediately if none of our scrollbars was hit
  457.     }
  458.  
  459.     //    dispatch on partCode
  460.     switch ( partCode )
  461.     {
  462.         case kControlIndicatorPart:
  463.             // click in thumb: call TrackControl with no actionProc and adjust text
  464.             TrackControl( bar, hitPt, nil );
  465.             LCSynch( bar );
  466.             ScrollBarChanged( window );
  467.             return;
  468.  
  469.         case kControlUpButtonPart:
  470.             step = - ( ( modifiers & optionKey ) ? 1 : kScrollDelta );
  471.             break;
  472.  
  473.         case kControlDownButtonPart:
  474.             step = + ( ( modifiers & optionKey ) ? 1 : kScrollDelta );
  475.             break;
  476.  
  477.         case kControlPageUpPart:
  478.             step = - ( pageSize - kScrollDelta );
  479.             break;
  480.  
  481.         case kControlPageDownPart:
  482.             step = + ( pageSize - kScrollDelta );
  483.             break;
  484.  
  485.     }    // switch
  486.  
  487.     //    save step in a static variable for our ScrollProc callback
  488.     sScrollStep = step;
  489.  
  490.     //    track the mouse
  491.     TrackControl( bar, hitPt, sScrollerUPP );
  492. }
  493.  
  494. /*
  495.     This is a callback routine called whenever the text is scrolled automaticall.
  496.     Since auto-scrolling is enabled, WEScroll may be invoked internally by WASTE
  497.     in many different circumstances, and we want to be notified when this happens
  498.     so we can adjust the scroll bars
  499. */
  500.  
  501. static pascal void TextScrolled( WEReference we )
  502. {
  503.     WindowRef        window = nil;
  504.  
  505.     //    retrieve the window pointer stored in the WE instance as a "reference constant"
  506.     if ( WEGetInfo( weRefCon, &window, we ) != noErr )
  507.         return;
  508.  
  509.     //    make sure the scroll bars are in synch with the destination rectangle
  510.     AdjustBars( window );
  511. }
  512.  
  513. Boolean    DoContent( Point hitPt, const EventRecord *event, WindowRef window )
  514. {
  515.     WEReference        we;
  516.     Rect            textRect;
  517.     GrafPtr            savePort;
  518.     Boolean            inBackground, handleClick, retval;
  519.  
  520.     retval = false; // false means click should not activate this window
  521.     we = GetWindowWE(window);
  522.  
  523.     //    is this windowd in the background?
  524.     inBackground = ! IsWindowHilited( window );
  525.  
  526.     //    set the port to our window's port
  527.     GetPort( &savePort );
  528.     SetPortWindowPort( window );
  529.  
  530.     //    convert the point to local coordinates
  531.     GlobalToLocal( &hitPt );
  532.  
  533.     //    a click in an inactive window should normally activate it,
  534.     //    but the availability of the Drag Manager introduces an exception to this rule:
  535.     //    a click in the background selection may start a drag gesture,
  536.     //    without activating the window
  537.  
  538.     if ( inBackground )
  539.     {
  540.         if ( gHasDragAndDrop )
  541.         {
  542.             long selStart, selEnd;
  543.             RgnHandle selRgn;
  544.  
  545.             WEGetSelection( &selStart, &selEnd, we );
  546.             selRgn = WEGetHiliteRgn( selStart, selEnd, we );
  547.             handleClick = PtInRgn( hitPt, selRgn ) && WaitMouseMoved( event->where );
  548.             DisposeRgn( selRgn );
  549.         }
  550.         else
  551.         {
  552.             handleClick = false; // no DragManager: never click-through
  553.         }
  554.     }
  555.     else
  556.     {
  557.         handleClick = true;    // window is frontmost: always handle click
  558.     }
  559.  
  560.     if ( handleClick )
  561.     {
  562.         CalcTextRect( window, &textRect );
  563.  
  564.         if ( PtInRect( hitPt, &textRect ) )
  565.         {
  566.             WEClick( hitPt, event->modifiers, event->when, we );
  567.         }
  568.         else
  569.         {
  570.             DoScrollBar( hitPt, event->modifiers, window );
  571.         }
  572.     }
  573.     else
  574.     {
  575.         retval = inBackground;
  576.     }
  577.  
  578.     //    restore the port
  579.     SetPort( savePort );
  580.  
  581.     return retval;
  582. }
  583.  
  584.  
  585. static void    DoScrollKey( short keyCode, WindowRef window )
  586. {
  587.     DocumentHandle        hDocument;
  588.     ControlRef            bar;
  589.     long                value;
  590.     LongRect            viewRect;
  591.  
  592.     hDocument = GetWindowDocument(window);
  593.     bar = (*hDocument)->scrollBars[ v ];
  594.  
  595.     //    get current scroll bar value
  596.     value = LCGetValue( bar );
  597.  
  598.     //    get text view rect
  599.     WEGetViewRect( &viewRect, (*hDocument)->we );
  600.  
  601.     switch ( keyCode )
  602.     {
  603.  
  604.         case keyPgUp:
  605.             value -= ( viewRect.bottom - viewRect.top ) - kScrollDelta;
  606.             break;
  607.  
  608.         case keyPgDn:
  609.             value += ( viewRect.bottom - viewRect.top ) - kScrollDelta;
  610.             break;
  611.  
  612.         case keyHome:
  613.             value = 0;
  614.             break;
  615.  
  616.         case keyEnd:
  617.             value = LONG_MAX;
  618.             break;
  619.     }    // switch
  620.  
  621.     //    set the new scroll bar value and scroll the text pane accordingly
  622.  
  623.     LCSetValue( bar, value );
  624.     ScrollBarChanged( window );
  625. }
  626.  
  627. void DoKey( short key, const EventRecord *event )
  628. {
  629.     WindowRef window;
  630.     short keyCode;
  631.  
  632.     //    do nothing if no window is active
  633.     if ( ( window = FrontWindow( ) ) == nil )
  634.         return;
  635.  
  636.     //    extract virtual key code from event record
  637.     keyCode = ( event->message & keyCodeMask ) >> 8 ;
  638.  
  639.     // page movement keys are handled by DoScrollKey()
  640.     switch ( keyCode )
  641.     {
  642.         case keyPgUp:
  643.         case keyPgDn:
  644.         case keyHome:
  645.         case keyEnd:
  646.             DoScrollKey( keyCode, window );
  647.             break;
  648.  
  649.         default:
  650.             WEKey( key, event->modifiers, GetWindowWE(window) );
  651.             break;
  652.     }
  653. }
  654.  
  655. void DoUpdate( WindowRef window )
  656. {
  657.     GrafPtr        savePort;
  658.     RgnHandle    updateRgn;
  659.  
  660.     // if we have no windows, there's nothing to update!
  661.     if ( window == nil )
  662.         return;
  663.  
  664.     // save the old drawing port
  665.     GetPort( &savePort );
  666.     SetPortWindowPort( window );
  667.  
  668.     // notify everything that we're doing an update.
  669.     BeginUpdate( window );
  670.  
  671.     // BeginUpdate sets the window port visRgn to the region to update
  672.     updateRgn = GetWindowPort(window)->visRgn;
  673.  
  674.     if ( !EmptyRgn( updateRgn ) )    // if it's not an empty region, let's update it!
  675.     {
  676.         // erase the update region
  677.         EraseRgn( updateRgn );
  678.  
  679.         //    draw scroll bars
  680.         UpdateControls( window, updateRgn );
  681.  
  682.         //    draw grow icon
  683.         MyDrawGrowIcon( window, false );
  684.  
  685.         //    draw text
  686.         WEUpdate( updateRgn, GetWindowWE( window ) );
  687.     }
  688.  
  689.     // tell everything we're done updating
  690.     EndUpdate( window );
  691.  
  692.     // restore the old graphics port
  693.     SetPort( savePort );
  694. }
  695.  
  696.  
  697. void    DoActivate( Boolean activFlag, WindowRef window )
  698. {
  699.     DocumentHandle        hDocument;
  700.     WEReference            we;
  701.     GrafPtr                savePort;
  702.     Rect                barRect;
  703.     ControlPartCode        barHilite;
  704.     short                menuID;
  705.     VHSelect            axis;
  706.  
  707.     // if this is not one of our document windows, nothing to do here...
  708.     if ( ( hDocument = GetWindowDocument(window) ) == nil )
  709.         return;
  710.     we = (*hDocument)->we;
  711.  
  712.     //     set up the port
  713.     GetPort( &savePort );
  714.     SetPortWindowPort( window );
  715.  
  716.     // activate or deactivate the text (and any other relevant stuff) depending on just
  717.     // what we're doing here...
  718.     if ( activFlag )
  719.     {
  720.         WEActivate( we );
  721.         barHilite = kControlNoPart;
  722.     }
  723.     else
  724.     {
  725.         WEDeactivate( we );
  726.         barHilite = kControlDisabledPart;
  727.     }
  728.  
  729.     //    redraw the grow icon (and validate its rect)
  730.     MyDrawGrowIcon( window, true );
  731.  
  732.     //    redraw the scroll bars with the new highlighting (and validate their rects)
  733.     for ( axis = v; axis <= h; axis++ )
  734.     {
  735.         HiliteControl( (*hDocument)->scrollBars[ axis ], barHilite );
  736.         CalcScrollBarRect( window, axis, &barRect );
  737.         ValidRect( &barRect );
  738.     }
  739.  
  740.     //    dim or undim text-related menus
  741.     for ( menuID = kMenuEdit; menuID <= kMenuFeatures; menuID++ )
  742.     {
  743.         if ( activeFlag )
  744.             EnableItem( GetMenuHandle( menuID ), 0 );
  745.         else
  746.             DisableItem( GetMenuHandle( menuID ), 0 );
  747.     }
  748.  
  749.     // invalidate the menu bar
  750.     InvalMenuBar( );
  751.  
  752.     // restore the old graphics port..
  753.     SetPort( savePort );
  754. }
  755.  
  756. OSErr CreateWindow( const FSSpec *pFileSpec )
  757. {
  758.     DocumentHandle    hDocument = nil;
  759.     WindowRef        window = nil;
  760.     AliasHandle        alias = nil;
  761.     WEReference        we = nil;
  762.     ControlRef        bar = nil;
  763.     FInfo            fileInfo;
  764.     Rect            textRect;
  765.     LongRect        longTextRect;
  766.     VHSelect        axis;
  767.     OSErr            err;
  768.  
  769. #ifdef __cplusplus
  770.     static WEScrollUPP sScrollerUPP = NewWEScrollProc( TextScrolled );
  771. #else
  772.     static WEScrollUPP sScrollerUPP = nil;
  773.     if ( sScrollerUPP == nil )
  774.     {
  775.         sScrollerUPP = NewWEScrollProc( TextScrolled );
  776.     }
  777. #endif
  778.  
  779.     //    allocate a relocateable block to hold a document record
  780.     hDocument = (DocumentHandle) NewHandleClear( sizeof( DocumentRecord ) );
  781.     if ( ( err = MemError( ) ) != noErr )
  782.         goto cleanup;
  783.  
  784.     //    create the window from a 'WIND' template: the window is initially invisible
  785.     //    if ColorQuickDraw is available, create a color window
  786.     if ( gHasColorQD )
  787.     {
  788.         window = GetNewCWindow( kWindowTemplateID, nil, (WindowRef) -1L );
  789.     }
  790.     else
  791.     {
  792.         window = GetNewWindow( kWindowTemplateID, nil, (WindowRef) -1L );
  793.     }
  794.  
  795.     //    make sure we got a window
  796.     if ( window == nil )
  797.     {
  798.         err = memFullErr;
  799.         goto cleanup;
  800.     }
  801.  
  802.     // link the document record to the window and the other way around
  803.     SetWRefCon(window, (long) hDocument);
  804.     (*hDocument)->owner = window;
  805.  
  806.     // we got a window, so tell QuickDraw where to draw...
  807.     SetPortWindowPort( window );
  808.  
  809.     //    calculate the text rectangle
  810.     CalcTextRect( window, &textRect );
  811.     WERectToLongRect( &textRect, &longTextRect );
  812.  
  813.     //    create a new WASTE instance
  814.     if ( ( err = WENew( &longTextRect, &longTextRect, weDoAutoScroll +
  815.                                                weDoOutlineHilite +
  816.                                                weDoUndo +
  817.                                                weDoIntCutAndPaste +
  818.                                                weDoDragAndDrop +
  819.                                                weDoUseTempMem +
  820.                                                weDoDrawOffscreen, &we) ) != noErr )
  821.         goto cleanup;
  822.  
  823.     // set the alignment to weFlushLeft so "slop recalc" is disabled
  824.     WESetAlignment( weFlushLeft, we );
  825.  
  826.     //    save a reference to the window in the WE instance
  827.     if ( ( err = WESetInfo( weRefCon, &window, we ) ) != noErr )
  828.         goto cleanup;
  829.  
  830.     //    now the other way around:  save the WE reference in the document record
  831.     (*hDocument)->we = we;
  832.  
  833.     //    set up our scroll callback
  834.     if ( ( err = WESetInfo( weScrollProc, &sScrollerUPP, we ) ) != noErr )
  835.         goto cleanup;
  836.  
  837.     //    create the scroll bars from a control template
  838.     for ( axis = v; axis <= h; axis++ )
  839.     {
  840.         if ( ( bar = GetNewControl( kScrollBarTemplateID, window ) ) == nil )
  841.         {
  842.             err = memFullErr;
  843.             goto cleanup;
  844.         }
  845.  
  846.         HiliteControl( bar, kControlDisabledPart );
  847.  
  848.         //    attach a LongControl record to the scroll bar:  this allows us to use long
  849.         //    settings and thus scroll text taller than 32,767 pixels
  850.         if ( ( err = LCAttach( bar ) ) != noErr )
  851.             goto cleanup;
  852.  
  853.         //    save control handle in the document record
  854.         (*hDocument)->scrollBars[ axis ] = bar;
  855.  
  856.     }    // for
  857.  
  858.     //    ViewChanged( ) adjusts the scroll bars rectangles to the window frame
  859.     ViewChanged( window );
  860.  
  861.     //    if pFileSpec is not nil, it points to a file to read, so let's read it!
  862.     if ( pFileSpec != nil )
  863.     {
  864.         // turn the cursor into a wristwatch because this can be a lengthy operation
  865.  
  866.         SetCursor( * GetCursor( watchCursor ) );
  867.  
  868.         //    retrieve file infomation
  869.  
  870.         if ( ( err = FSpGetFInfo( pFileSpec, &fileInfo ) ) != noErr )
  871.             goto cleanup;
  872.  
  873.         //    make sure we recognize the file type
  874.         if ( (fileInfo.fdType != kTypeText ) && ( fileInfo.fdType != ftSimpleTextDocument ) )
  875.         {
  876.             err = -1;
  877.             goto cleanup;
  878.         }
  879.  
  880.         //    read in the file
  881.         if ( ( err = ReadTextFile( pFileSpec, we ) ) != noErr )
  882.             goto cleanup;
  883.  
  884.         //    set the window title to the file name
  885.         SetWTitle( window, pFileSpec->name );
  886.  
  887.         //    create an alias to keep track of the file
  888.         if ( ( err = NewAlias( nil, pFileSpec, &alias ) ) != noErr )
  889.             goto cleanup;
  890.         (*hDocument)->fileAlias = (Handle) alias;
  891.  
  892.         //    if the file is a read-only file, go ahead and enable those flags
  893.         if (fileInfo.fdType == ftSimpleTextDocument )
  894.         {
  895.             WEFeatureFlag( weFReadOnly, weBitSet, we );
  896.         }
  897.  
  898.         //    let's make sure the cursor is happy...
  899.         InitCursor( );
  900.  
  901.     }
  902.  
  903.     //    adjust scroll bar settings based on the total text height
  904.     AdjustBars( window );
  905.  
  906.     //    finally!  show the document window
  907.     ShowWindow( window );
  908.  
  909. cleanup:
  910.     if ( err != noErr )
  911.     {
  912.         ErrorAlert( err );
  913.     }
  914.     return err;
  915. }
  916.  
  917. void DestroyWindow( WindowRef window )
  918. {
  919.     DocumentHandle    hDocument;
  920.     short            menuID;
  921.  
  922.     hDocument = GetWindowDocument(window);
  923.  
  924.     //    destroy the WE record
  925.  
  926.     WEDispose( (*hDocument)->we );
  927.  
  928.     //    destory the LongControl records attached to the scroll bars
  929.  
  930.     LCDetach( (*hDocument)->scrollBars[ v ] );
  931.     LCDetach( (*hDocument)->scrollBars[ h ] );
  932.  
  933.     //    dispose of the file alias, if any
  934.  
  935.     ForgetHandle( & ((*hDocument)->fileAlias) );
  936.  
  937.     //    destroy the window record and all associated data structures
  938.  
  939.     DisposeWindow( window );
  940.  
  941.     //    finally, dispose of the document record
  942.  
  943.     DisposeHandle( (Handle) hDocument );
  944.  
  945.     // adjust the menus to suit
  946.  
  947.     for ( menuID = kMenuFont; menuID <= kMenuFeatures; menuID++ )
  948.         DisableItem( GetMenuHandle( menuID ), 0 );
  949.     InvalMenuBar();
  950. }
  951.